#pragma once

#include "vector.h"

namespace g3 {

template <typename T>
basic_vector<T> tri_normal(const basic_vector<T> & v0, const basic_vector<T> & v1, const basic_vector<T> & v2)
{
	basic_vector<T> n = outer_product<T>(v1 - v0, v2 - v0);
	if (n != basic_vector<T>(0, 0, 0))
		n /= sqrt(n.x * n.x + n.y * n.y + n.z * n.z);
	return n;
}

/** 
	Projects the point p on the segment (p0, p1);
	degenerate is set to true when the segment is too short (in such case,
	other parameters are not computed, and the function returns false);
	h2 receives the squared distance from p to the segment line
	t receives the parameter along the segment line of the projection
	p* = p0 + (p1 - p0) * t;
	Returns true if the projection falls inside the segment
*/
template <typename T>
bool project_point_on_segment(const basic_vector<T> & p, 
	const basic_vector<T> & p0, const basic_vector<T> & p1, 
	bool & degenerate, T & h2, T & t);

/**
	Projects one of the crossing segments (p0, p1) and (q0, q1) on another;
	collinear is set to true when the segments are nearly collinear (in such case,
	other parameters are not computed, and the function returns true if two segments overlap);
	h receives the distance between the two segments;
	s receives projection parameter along (p0, p1);
	t receives projection parameter along (q0, q1);
	Returns true if projections lie inside each segment
*/
template <typename T>
bool cross_segments(const basic_vector<T> & p0, const basic_vector<T> & p1, 
	const basic_vector<T> & q0, const basic_vector<T> & q1, 
	bool & collinear, T & h, T & s, T & t);

/** 
	Projects the point p on the triangular face (q0, q1, q2);
	h receives the distance from p to the face plane;
	b receives barycentric coordinates of the projection point
	Returns true if projetion lies inside the triangle
*/
template <typename T>
bool project_point_on_triangle(const basic_vector<T> & p,
	const basic_vector<T> & q0, const basic_vector<T> & q1, const basic_vector<T> & q2,
	bool & degenerate, T & h, T b[3]);

/** 
	Finds intersection of the segment (p0, p1) and the triangular face (q0, q1, q2);
	degenerate is set to true if either the segment or the face is degenerate (in such case,
	other parameters are not computed, and the function returns false);
	t receives parameter along (p0, p1) of the intersection point;
	b receives barycentric coordinates of the intersection point
*/
template <typename T>
bool intersect_segment_and_triangle(const basic_vector<T> & p0, const basic_vector<T> & p1,
	const basic_vector<T> & q0, const basic_vector<T> & q1, const basic_vector<T> & q2,
	bool & degenerate, T b[3], T & t);


/**
	Returns distance from the point to the segment (unsigned!).
	h2 receives the squared distance from p to the segment line
	t receives the parameter along the segment line of the projection
	p* = p0 + (p1 - p0) * t;
	If degenerate is true, h2 is not computed.
*/
template <typename T>
T distance_to_segment(const basic_vector<T> & p, 
	const basic_vector<T> & p0, const basic_vector<T> & p1, 
	bool & degenerate, T & h2, T & t);

/**
	Returns distance from the point to the triangle (unsigned!).
	h receives the signed distance from p to the face plane;
	b receives barycentric coordinates of the projection point.
	If degenerate is true, h is not computed.
*/
template <typename T>
T distance_to_triangle(const basic_vector<T> & p,
	const basic_vector<T> & q0, const basic_vector<T> & q1, const basic_vector<T> & q2,
	bool & degenerate, T & h, T b[3]);

/**
	Given two sets of vertices, S1 and S2, returns indices of vertices of S2 in S1. 
	If a vertex from S2 has no counterpart in S1, it is assigned an index -1.
*/
template <typename T>
void get_vertex_indices(
	const std::vector< basic_vector<T> > & S1, 
	const hash_grid<int> & grid, 
	const std::vector< basic_vector<T> > & S2, 
	std::vector<int> & indices, // output
	T tolerance,
	bool required = false);

}

#include "algorithm.inl"